namespace Plugins.Serializer
{
    using System;
    using System.ComponentModel;
    using System.IO;
    using System.Security;
    using System.Xml;
    using System.Xml.Serialization;
    using Plugins.Interfaces;
    using Plugins.Library;
    using Plugins.Serializer.Internal;

    [Serializable]
    public abstract class PluginStreamSerializer<T> : IPluginStreamSerializer<T>
    {
        [NonSerialized]
        private static readonly PluginFormatterCache _formatters = new PluginFormatterCache();
        [NonSerialized]
        private static readonly PluginSerializerCache _serializers = new PluginSerializerCache();

        private T _object;
        private readonly Type _type = typeof(T);

        protected virtual bool Deserialize(Stream input, IPluginTypeFormatter formatter)
        {
            this._object = default(T);
            try
            {
                IPluginRuntimeSerializerInternal serializer = PluginRuntimeHelper.GetSerializer(typeof(T), formatter);
                if (serializer != null)
                {
                    serializer.CreateRuntimeSerializer(false);
                    using (XmlReader xmlReader = XmlReader.Create(input, serializer.ReaderSettings))
                    {
                        XmlSerializer cache = PluginStreamSerializer<T>._serializers[serializer];
                        if (cache != null)
                        {
                            object result = cache.Deserialize(xmlReader);
                            if (result != null)
                            {
                                this._object = (T) result;
                            }
                        }
                    }
                }
                return true;
            }
            catch (FileLoadException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (FileNotFoundException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (IOException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (ArgumentNullException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (SecurityException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (AccessViolationException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (ApplicationException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (FormatException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (ArgumentException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (UnauthorizedAccessException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (InvalidOperationException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (Win32Exception ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            return false;
        }

        protected bool OverrideRuntimeSerializer(IPluginTypeFormatter formatter, XmlSerializer value)
        {
            IPluginRuntimeSerializerInternal serializer = PluginRuntimeHelper.GetSerializer(typeof(T), formatter);
            return ((serializer != null) && PluginStreamSerializer<T>._serializers.Override(serializer, value));
        }

        protected virtual bool Serialize(T obj, Stream output, IPluginTypeFormatter formatter)
        {
            this._object = obj;
            try
            {
                IPluginRuntimeSerializerInternal serializer = PluginRuntimeHelper.GetSerializer(typeof(T), formatter);
                if (serializer != null)
                {
                    serializer.CreateRuntimeSerializer(false);
                    using (XmlWriter xmlWriter = XmlWriter.Create(output, serializer.WriterSettings))
                    {
                        XmlSerializer cache = PluginStreamSerializer<T>._serializers[serializer];
                        if (cache != null)
                        {
                            cache.Serialize(xmlWriter, obj);
                        }
                    }
                    return true;
                }
            }
            catch (FileLoadException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (FileNotFoundException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (IOException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (ArgumentNullException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (SecurityException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (AccessViolationException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (ApplicationException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (FormatException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (ArgumentException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (UnauthorizedAccessException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (InvalidOperationException ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            catch (Win32Exception ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
            return false;
        }

        bool IPluginStreamSerializer<T>.Deserialize(Stream input)
        {
            IPluginTypeFormatter formatter = PluginStreamSerializer<T>._formatters[this._type];
            return this.Deserialize(input, formatter);
        }

        bool IPluginStreamSerializer<T>.Deserialize(Stream input, IPluginRuntimeFormatter value)
        {
            IPluginTypeFormatter formatter = PluginStreamSerializer<T>._formatters[value];
            return ((formatter != null) && this.Deserialize(input, formatter));
        }

        bool IPluginStreamSerializer<T>.Serialize(T obj, Stream output)
        {
            IPluginTypeFormatter formatter = PluginStreamSerializer<T>._formatters[this._type];
            return this.Serialize(obj, output, formatter);
        }

        bool IPluginStreamSerializer<T>.Serialize(T obj, Stream output, IPluginRuntimeFormatter value)
        {
            IPluginTypeFormatter formatter = PluginStreamSerializer<T>._formatters[value];
            return ((formatter != null) && this.Serialize(obj, output, formatter));
        }

        public T RuntimeObject
        {
            get
            {
                return this._object;
            }
        }

        protected void InitializeRuntimeObject(T obj)
        {
            this._object = obj;
        }

        protected IPluginTypeFormatter XmlTypeFormatter
        {
            get
            {
                return PluginStreamSerializer<T>._formatters[this._type];
            }
        }
    }
}

